#ifndef __CPOFSM_H__
#define __CPOFSM_H__

#include "cpolist.h"

/* 系统状态机类型 */
typedef enum _cpo_fsm_tp_e{
    S_SYS_INIT = 0,     // 必须从0开始，要和cpo_sysfsmset[]的第0个成员对应
    S_SYSPOINTS_WAIT,   // 要和 cpo_sysfsmset[]的第1个成员对应
    S_SYS_IDLE,         // 要和 cpo_sysfsmset[]的第2个成员对应

    S_SUBSYS_INIT = 5,  // !!要和cpo_fsmsets_t cpo_subfsms[]的第5个成员对应!!
    S_IVWP_WAIT,        // 要和cpo_fsmsets_t cpo_subfsms[]的第6个成员对应
    S_CH_WAIT,
    S_SUBSYS_IDLE
}cpo_fsm_tp_e;

/* 事件类型 */
typedef enum _cpo_ev_tp_e{
    /* 系统状态机事件 */
    EV_SYS_START    =   0,
    EV_SYS_STOP     =   1,
    EV_SYSPOINTS_ON     =   2,
    EV_TO_SYS_STOP      =   3,
    /* 子状态的事件 */
    EV_SUBSYS_START =   6,
    EV_WP_ON        =   7,
    EV_CH_ON        =   8,
    EV_SUBSYS_STOP
}cpo_ev_tp_e;

/* 状态机转移 */
typedef struct _cpo_fsmtrans_t{
    cpo_ev_tp_e event;
    int (*pre)(void *);        // 预处理，判断是否满足状态转移条件
    int (*action)(void *);     // 执行，执行成功，状态就变成下一个状态了
    int (*end)(void *);        // 收尾
    cpo_fsm_tp_e next_state;
}cpo_fsmtrans_t;

/* 状态机转移集合 */
typedef struct _cpo_fsmsets_t{
    char name[30];
    int num;
    cpo_fsmtrans_t *cpo_fsm;
}cpo_fsmsets_t;

/* 关联在一起的设备, 组成一个子状态机 */
struct _subfsm_sn_t{
    int ch_sn;      // [0]-冷机
    int pchwp_sn;   // [1]-冷却水泵
    int cwp_sn;     // [2]-冷冻水泵
    int ct_sn;      // [3]-冷却塔号
};

/* 如果是子状态机, 就加到 cpo_fsm_head_l 的链表中 */
typedef struct _cpo_fsm_t{
    cpo_fsmsets_t *fsmset;
    int fsmno;  // 状态机号: 
                //      系统状态机: SYS_FSM 
                //      子状态机: bind_dev.ch_sn是一致的

    struct _subfsm_sn_t bind_dev;   // 记录绑定的水泵、冷却塔号

    cpo_fsm_tp_e pre_state;
    cpo_fsm_tp_e cur_state;

    cpo_ev_tp_e fsmevt;         // 记录当前收到的事件

    bool all_stop;  // true: 所有的设备都已经停止
                    // 一个子状态机刚启动时置false, 子状态机所有设备都停止后置true

    struct list_head list;      // 作为子节点，用于关联状态机

    /* 不需要冷机链表，因为子状态机就是根据冷机号创建的，
     * 所以直接根据fsmno从cpo_dev->ch_head中找到冷机描述符即可
     */
    struct list_head v_clist;   // 作为头节点，用于关联冷机两侧水阀开关点位
    struct list_head v_slist;   // 作为头节点，用于关联冷机两侧水阀开关状态点位

    struct list_head ct_clist;  // 作为头节点，用于关联冷机两侧水阀开关点位
    struct list_head ct_slist;  // 作为头节点，用于关联冷机两侧水阀开关状态点位

    struct list_head wp_clist;  // 作为头节点，用于关联冷冻水泵和冷却水泵开关点位
    struct list_head wp_slist;  // 作为头节点，用于关联冷冻水泵和冷却水泵开关状态
}cpo_fsm_t;

/* 状态机头节点 */
typedef struct _cpo_fsm_head_l{
    struct list_head list;
}cpo_fsm_head_l;

void *cpo_state_ck_thread(void *arg);
void send_event_2sysfsm(cpo_ev_tp_e tp);
void send_event_2subfsm(cpo_ev_tp_e tp, int fsmno);


enum error_code fsm_init_2init_pre(void *);
enum error_code fsm_init_2init(void *);
enum error_code fsm_init_2init_end(void *);

enum error_code cpo_fsmpre_null(void *);
enum error_code cpo_fsmaction_null(void *);
enum error_code cpo_fsmend_null(void *);

enum error_code fsm_sys_init_2wait_pre(void *);
enum error_code fsm_sys_init_2wait(void *);
enum error_code fsm_sys_init_2wait_end(void *);

enum error_code fsm_sys_wait_2init_pre(void *);
enum error_code fsm_sys_wait_2init(void *);
enum error_code fsm_sys_wait_2init_end(void *);

enum error_code fsm_sys_wait_2idle(void *);
enum error_code fsm_sys_wait_2idle_pre(void *);
enum error_code fsm_sys_wait_2idle_end(void *);

enum error_code fsm_sys_idle_2init_pre(void *);
enum error_code fsm_sys_idle_2init(void *);
enum error_code fsm_sys_idle_2init_end(void *);

enum error_code fsm_init_2ivwpwait(void *);
enum error_code fsm_init_2ivwpwait_end(void *);

enum error_code fsm_ivwpwait_2chwait_pre(void *);
enum error_code fsm_ivwpwait_2chwait(void *);
enum error_code fsm_ivwpwait_2chwait_end(void *);

enum error_code fsm_ivwpwait_2init_pre(void *);
enum error_code fsm_ivwpwait_2init(void *);
enum error_code fsm_ivwpwait_2init_end(void *);

enum error_code fsm_chwait_2idle_pre(void *);

enum error_code fsm_chwait_2ivwpwait_pre(void *);
enum error_code fsm_chwait_2ivwpwait(void *);
enum error_code fsm_chwait_2ivwpwait_end(void *);

enum error_code fsm_idle_2chwait_pre(void *);
enum error_code fsm_idle_2chwait(void *);
enum error_code fsm_idle_2chwait_end(void *);

void fsm_do(cpo_ev_tp_e event, cpo_fsm_t *fsm);

#endif // __CPOFSM_H__